package cn.jolyoulu.common.poi.excel.reader.sax;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.*;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
import cn.jolyoulu.common.poi.excel.reader.handler.ExcelReaderHandler;

import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;

/**
 * @Author: JolyouLu
 * @Date: 2023/12/31 18:27
 * @Description @Description Sax模式下读取图片的Handler
 */
@Slf4j
public class SaxDrawingReaderHandler extends DefaultHandler {

    /**
     * 处理每一个单元格的Handler
     */
    private ExcelReaderHandler<SaxDrawingReaderHandler.Image> cellHandler;

    /**
     * excel文件包
     */
    private OPCPackage pkg;

    /**
     * drawing的xml文件
     */
    private PackagePart drawingPkg;

    /**
     * 行
     */
    private Integer row;

    /**
     * 行可读标记
     */
    private boolean rowRead;

    /**
     * 列
     */
    private Integer column;

    /**
     * 列可读标记
     */
    private boolean columnRead;

    /**
     * 图片关联id
     */
    private String relationshipId;

    /**
     * 图片
     */
    private Image image;

    public SaxDrawingReaderHandler(OPCPackage pkg, PackagePart drawingPkg, ExcelReaderHandler<SaxDrawingReaderHandler.Image> cellHandler) {
        this.cellHandler = cellHandler;
        this.pkg = pkg;
        this.drawingPkg = drawingPkg;
    }

    /**
     * 当读取到开始的标签会触发这个方法
     * 例: <c><v>abc<v/><c/> 顺序 <c> => <v>
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) {
        //进入一个图片标签，清空所有记录
        if (qName.equals("xdr:twoCellAnchor")) {
            this.row = 0;
            this.column = 0;
        }
        if (qName.equals("xdr:row")) {
            this.rowRead = true;
        }
        if (qName.equals("xdr:col")) {
            this.columnRead = true;
        }
        if (qName.equals("a:blip")) {
            this.relationshipId = attributes.getValue("r:embed");
        }
    }

    /**
     * 当读取到结束的标签会触发这个方法
     * 例: <c><v>abc<v/><c/> 顺序 <v/> => <c/>
     */
    @Override
    public void endElement(String uri, String localName, String qName) {
        try {
            //退出一个图片标签
            if (qName.equals("xdr:twoCellAnchor")) {
                PackageRelationship relationship = drawingPkg.getRelationship(this.relationshipId);
                PackagePart imagePk = pkg.getPart(PackagingURIHelper.createPartName(relationship.getTargetURI()));
                if (Objects.nonNull(imagePk)) {
                    byte[] bytes;
                    //读取字节数据
                    try (InputStream is = imagePk.getInputStream()) {
                        bytes = new byte[is.available()];
                        is.read(bytes);
                    }
                    PackagePartName pkPartName = imagePk.getPartName();
                    this.image = new Image(bytes, pkPartName.getExtension());
                    //处理数据
                    cellHandler.handler(this.row, this.column, this.image);
                }
                //重置数据
                this.row = 0;
                this.column = 0;
                this.rowRead = false;
                this.columnRead = false;
                this.image = null;
            }
        } catch (InvalidFormatException | IOException e) {
            log.error("解析图片失败", e);
        }
    }

    /**
     * 当读取到值时会触发这个方法
     * 例: <c><v>abc<v/><c/> 顺序 <v>abc<v/>
     */
    @Override
    public void characters(char[] ch, int start, int length) {
        if (rowRead) {
            this.row = Integer.valueOf(new String(ch, start, length));
            this.rowRead = false;
        }
        if (columnRead) {
            this.column = Integer.valueOf(new String(ch, start, length));
            this.columnRead = false;
        }
    }

    @Getter
    public static class Image {
        /**
         * 文件字节
         */
        private byte[] bytes;
        /**
         * 文件后缀
         */
        private String suffix;

        public Image(byte[] bytes, String suffix) {
            this.bytes = bytes;
            this.suffix = suffix;
        }
    }
}
